#include "../include/utils.h"
#include <string.h>
#ifdef WIN32
#include <Windows.h>
#else
#include <netinet/in.h>
#endif // WIN32


int is_big_endian() {
  unsigned short test = 0x1122;
  return *((unsigned char *)&test) == 0x11;
}

uint64_t ntohll(uint64_t val) {
  if (!is_big_endian()) {
    return (((uint64_t)htonl((uint32_t)((val << 32) >> 32))) << 32) |
           (uint32_t)htonl((int)(val >> 32));
  }
  return val;
}

uint64_t htonll(uint64_t val) {
  if (!is_big_endian()) {
    return (((uint64_t)htonl((uint32_t)((val << 32) >> 32))) << 32) |
           (uint32_t)htonl((int)(val >> 32));
  }
  return val;
}

char *push_int8(char *dst, int8_t value) {
  dst[0] = (char)value;
  return dst + sizeof(value);
}

char *push_uint8(char *dst, uint8_t value) {
  dst[0] = (char)value;
  return dst + sizeof(value);
}

char *push_int16(char *dst, int16_t value) {
  value = htons(value);
  memcpy(dst, &value, sizeof(int16_t));
  return dst + sizeof(int16_t);
}

char *push_uint16(char *dst, uint16_t value) {
  value = htons(value);
  memcpy(dst, &value, sizeof(uint16_t));
  return dst + sizeof(uint16_t);
}

char *push_int32(char *dst, int32_t value) {
  value = htonl(value);
  memcpy(dst, &value, sizeof(int32_t));
  return dst + sizeof(int32_t);
}

char *push_uint32(char *dst, uint32_t value) {
  value = htonl(value);
  memcpy(dst, &value, sizeof(uint32_t));
  return dst + sizeof(uint32_t);
}

char *push_int64(char *dst, int64_t value) {
  value = htonll(value);
  memcpy(dst, &value, sizeof(int64_t));
  return dst + sizeof(int64_t);
}

char *push_uint64(char *dst, uint64_t value) {
  value = htonll(value);
  memcpy(dst, &value, sizeof(uint64_t));
  return dst + sizeof(uint64_t);
}

char *push_float(char *dst, float value) {
  memcpy(dst, &value, sizeof(float));
  return dst + sizeof(float);
}

char *push_double(char *dst, double value) {
  memcpy(dst, &value, sizeof(double));
  return dst + sizeof(double);
}

char *push_string(char *dst, const char *value, size_t size) {
  memcpy(dst, value, size);
  return dst + size;
}

const char *pop_int8(const char *src, int8_t *value) {
  *value = (int8_t)src[0];
  return src + sizeof(int8_t);
}

const char *pop_uint8(const char *src, uint8_t *value) {
  *value = (uint8_t)src[0];
  return src + sizeof(uint8_t);
}

const char *pop_int16(const char *src, int16_t *value) {
  memcpy(value, src, sizeof(int16_t));
  *value = ntohs(*value);
  return src + sizeof(int16_t);
}

const char *pop_uint16(const char *src, uint16_t *value) {
  memcpy(value, src, sizeof(uint16_t));
  *value = ntohs(*value);
  return src + sizeof(uint16_t);
}

const char *pop_int32(const char *src, int32_t *value) {
  memcpy(value, src, sizeof(int32_t));
  *value = ntohl(*value);
  return src + sizeof(int32_t);
}

const char *pop_uint32(const char *src, uint32_t *value) {
  memcpy(value, src, sizeof(uint32_t));
  *value = ntohl(*value);
  return src + sizeof(uint32_t);
}

const char *pop_int64(const char *src, int64_t *value) {
  memcpy(value, src, sizeof(int64_t));
  *value = ntohll(*value);
  return src + sizeof(int64_t);
}

const char *pop_uint64(const char *src, uint64_t *value) {
  memcpy(value, src, sizeof(uint64_t));
  *value = ntohll(*value);
  return src + sizeof(uint64_t);
}

const char *pop_float(const char *src, float *value) {
  memcpy(value, src, sizeof(float));
  return src + sizeof(float);
}

const char *pop_double(const char *src, double *value) {
  memcpy(value, src, sizeof(double));
  return src + sizeof(double);
}

const char *pop_string(const char *src, char *value, size_t size) {
  memcpy(value, src, size);
  return src + size;
}
